package top.up.demo.loadresources.service;

import lombok.extern.slf4j.Slf4j;
import org.springframework.core.io.ClassPathResource;
import org.springframework.stereotype.Service;
import top.up.demo.loadresources.utils.FileUtil;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.net.URLDecoder;
import java.nio.charset.StandardCharsets;
import java.util.Objects;

/**
 * 九种方式，读取 resources 目录下的文件路径
 *
 * @author <a href="mailto:lishuai2015@163.com">Jack.Li</a>
 * @version 1.0
 * @date 2024/01/13
 */
@Slf4j
@Service
public class LoadResourcesService {

    private static final String LOG_BRACKET = "【{}】";
    /**
     * 方式一：主要核心方法是使用 getResource 和 getPath 方法，这里的 getResource("") 里面是空字符串
     *
     * @param fileName 文件名
     * @throws IOException 异常
     */
    public void testMethod1(String fileName) throws IOException {
        //注意getResource("")里面是空字符串
        String path = Objects.requireNonNull(this.getClass().getClassLoader().getResource("")).getPath();
        log.info("获取路径部分：" + LOG_BRACKET, path);

        String filePath = path + fileName;
        log.info("获取路径 + 文件名：" + LOG_BRACKET, filePath);

        FileUtil.getFileContent(filePath);
    }

    /**
     * 方式二：直接通过文件名getPath来获取路径
     * <p/>
     * 主要核心方法是使用 getResource 和 getPath，直接通过 getResource(fileName) 获取文件路径，注意如果是路径方法中英文一定要使 用URLDecoder.decode 解密
     *
     * @param fileName 文件名
     * @throws IOException 异常
     */
    public void testMethod2(String fileName) throws IOException {
        String path = Objects.requireNonNull(this.getClass().getClassLoader().getResource(fileName)).getPath();//注意getResource("")里面是空字符串
        log.info("获取路径部分：" + LOG_BRACKET, path);

        log.info("Charset UTF_8 的 name() 值：" + LOG_BRACKET, StandardCharsets.UTF_8.name());
        log.info("Charset UTF_8 的 name() 值的类型：" + LOG_BRACKET, StandardCharsets.UTF_8.name().getClass());

        String filePath = URLDecoder.decode(path, StandardCharsets.UTF_8.name());//如果路径中带有中文会被URLEncoder,因此这里需要解码
        log.info("获取路径 + 文件名：" + LOG_BRACKET, filePath);

        FileUtil.getFileContent(filePath);
    }

    /**
     * 方式三：直接通过 文件名+getFile() 来获取
     * <p/>
     * 直接通过文件名+getFile()来获取文件。如果是文件路径的话getFile和getPath效果是一样的，如果URL路径的话getPath是参数的路径。
     *
     * @param fileName 文件名
     * @throws IOException 异常
     */
    public void testMethod3(String fileName) throws IOException {
        String path = this.getClass().getClassLoader().getResource(fileName).getFile();//注意getResource("")里面是空字符串
        log.info("获取路径部分：" + LOG_BRACKET, path);

        String filePath = URLDecoder.decode(path, StandardCharsets.UTF_8.name());//如果路径中带有中文会被URLEncoder,因此这里需要解码
        log.info("获取路径 + 文件名：" + LOG_BRACKET, filePath);

        FileUtil.getFileContent(filePath);
    }

    /**
     * 方式四：直接使用getResourceAsStream方法获取流 springboot项目中需要使用此种方法，因为jar包中没有一个实际的路径存放文件
     * <p/>
     * 使用getResourceAsStream方法获取流，上面的直接几种方式都需要获取文件路径，但是在SpringBoot中所有文件都在jar包中，没有一个实际的路径，因此可以使用下面的方式。
     *
     * @param fileName 文件名
     * @throws IOException 异常
     */
    public void testMethod4(String fileName) throws IOException {
        InputStream in = this.getClass().getClassLoader().getResourceAsStream(fileName);
        FileUtil.getFileContent(in);
    }

    /**
     * 【重要】方式五：直接使用getResourceAsStream方法获取流
     * 如果不使用getClassLoader，可以使用getResourceAsStream("/配置测试.txt")直接从resources根路径下获取
     * <p/>
     * 主要是使用getResourceAsStream方法获取流，不能使用直接从路径下获取， getClassLoaderSpringBoot中的所有文件都在jar包中，没有一个实际的路径，因此可以使用下面的根方式。getResourceAsStream("/配置测试.txt")``resources
     *
     * @param fileName 文件名
     * @throws IOException 异常
     */
    public void testMethod5(String fileName) throws IOException {
        InputStream in = this.getClass().getResourceAsStream(File.separator + fileName);
        FileUtil.getFileContent(in);
    }

    /**
     * 【重要】方式六：通过ClassPathResource类获取，建议SpringBoot中使用
     * springboot项目中需要使用此种方法，因为jar包中没有一个实际的路径存放文件
     * <p/>
     * 通过 ClassPathResource 类获取文件流，SpringBoot中的所有文件都在jar包中，没有一个实际的路径，因此可以使用下面的方式。
     *
     * @param fileName 文件名
     * @throws IOException 异常
     */
    public void testMethod6(String fileName) throws IOException {
        ClassPathResource classPathResource = new ClassPathResource(fileName);
        InputStream in = classPathResource.getInputStream();
        FileUtil.getFileContent(in);
    }

    /**
     * 方式七：通过绝对路径获取项目中文件的位置（不能用于服务器）
     *
     * @param fileName 文件名
     * @throws IOException 异常
     */
    public void testMethod7(String fileName) throws IOException {
        String rootPath = System.getProperty("user.dir");//E:\WorkSpace\Git\spring-framework-learning-example
        log.info("获取rootPath：" + LOG_BRACKET, rootPath);

        String filePath = rootPath + "\\src\\main\\resources\\" + fileName;
        log.info("获取filePath：" + LOG_BRACKET, filePath);

        FileUtil.getFileContent(filePath);
    }

    /**
     * 方式八：通过绝对路径获取项目中文件的位置（不能用于服务器）
     * <p/>
     * 通过new File("")获取的绝对路径，只是本地的绝对路径，不能用于服务器获取
     *
     * @param fileName 文件名
     * @throws IOException 异常
     */
    public void testMethod8(String fileName) throws IOException {
        //参数为空
        File directory = new File("");

        //规范路径：getCanonicalPath() 方法返回绝对路径，会把 ..\ 、.\ 这样的符号解析掉
        String rootCanonicalPath = directory.getCanonicalPath();

        //绝对路径：getAbsolutePath() 方法返回文件的绝对路径，如果构造的时候是全路径就直接返回全路径，如果构造时是相对路径，就返回当前目录的路径 + 构造 File 对象时的路径
        String rootAbsolutePath = directory.getAbsolutePath();

        log.info("getCanonicalPath() 方法返回绝对路径：" + LOG_BRACKET, rootCanonicalPath);
        log.info("getAbsolutePath() 方法返回绝对路径：" + LOG_BRACKET, rootAbsolutePath);

        String filePath = rootCanonicalPath + "\\src\\main\\resources\\" + fileName;
        FileUtil.getFileContent(filePath);
    }

    /**
     * 方式九：通过绝对路径获取项目中文件的位置
     * <p/>
     * 主要是通过设置环境变量，将文件传递到环境中，原理也是通过绝对路径获取的。
     * TEST_ROOT=E:\Test
     *
     * @param fileName 文件名
     * @throws IOException 异常
     */
    public void testMethod9(String fileName) throws IOException {
        try {
            System.setProperty("TEST_ROOT", "E:\\Test");
            //参数为空
            String rootPath = System.getProperty("TEST_ROOT");
            log.info("获取rootPath：" + LOG_BRACKET, rootPath);

            String filePath = rootPath + "\\src\\main\\resources\\" + fileName;
            FileUtil.getFileContent(filePath);
        } catch (FileNotFoundException ex) {
            log.error(ex.getMessage());
            throw new IOException(ex.getMessage());
        }

    }

}
